﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web.Mvc;
using Inovout.Data.Domain;

namespace Inovout.Web.Mvc
{
    public class CachedWidgetMetadataAttributes : CachedDataAnnotationsMetadataAttributes, IEnumerable<Attribute>
    {
        public CachedWidgetMetadataAttributes(IEnumerable<Attribute> attributes)
            : this(ExtractWidgetMetadataAttributes(attributes))
        {
        }
        private CachedWidgetMetadataAttributes(IList<Attribute> attributes)
            : base(attributes.ToArray())
        {
            this.Attributes = attributes;
            MergeWidgetMetadataAttributes(attributes);
        }
        public IEnumerable<Attribute> Attributes { get; private set; }
        private static IList<Attribute> ExtractWidgetMetadataAttributes(IEnumerable<Attribute> attributes)
        {
            //原子优先
            List<Attribute> extendAttributes = new List<Attribute>(attributes);
            DataPropertyAttribute widgetAttribute = attributes.OfType<DataPropertyAttribute>().FirstOrDefault();
            if (widgetAttribute != null)
            {
                extendAttributes.Add(new DisplayAttribute { Name = widgetAttribute.Alais, Order = widgetAttribute.Order ?? ModelMetadata.DefaultOrder });
                extendAttributes.Add(new DataTypeAttribute(widgetAttribute.DataType));
                if (!string.IsNullOrEmpty(widgetAttribute.DataFormat))
                {
                    extendAttributes.Add(new DisplayFormatAttribute { DataFormatString = widgetAttribute.DataFormat, ApplyFormatInEditMode = true });
                }
                if (widgetAttribute.Required)
                {
                    extendAttributes.Add(new RequiredAttribute());

                }
                switch (widgetAttribute.DataType)
                {
                    case System.ComponentModel.DataAnnotations.DataType.Text:
                        if (widgetAttribute.Max != null)
                        {
                            StringLengthAttribute stringLengthAttribute = new StringLengthAttribute(int.Parse(widgetAttribute.Max.ToString()));
                            if (widgetAttribute.Min != null)
                            {
                                stringLengthAttribute.MinimumLength = int.Parse(widgetAttribute.Min.ToString());
                            }
                            extendAttributes.Add(stringLengthAttribute);
                        }

                        break;
                    default:
                        break;
                }
            }

            AjaxValidationAttribute ajaxValidationAttribute = attributes.OfType<AjaxValidationAttribute>().FirstOrDefault();
            if (ajaxValidationAttribute != null)
            {
                extendAttributes.Add(new RemoteAttribute(ajaxValidationAttribute.Action, ajaxValidationAttribute.Controller, ajaxValidationAttribute.AreaName)
                {
                    AdditionalFields = ajaxValidationAttribute.AdditionalFields,
                    HttpMethod = ajaxValidationAttribute.HttpMethod,
                    ErrorMessage = ajaxValidationAttribute.ErrorMessage,
                    ErrorMessageResourceName = ajaxValidationAttribute.ErrorMessageResourceName,
                    ErrorMessageResourceType = ajaxValidationAttribute.ErrorMessageResourceType
                });
            }
            return extendAttributes;
        }

        internal void MergeAttributes(IEnumerable<Attribute> attributes)
        {
            MergeDataAnnotationsMetadataAttributes(attributes);
            MergeWidgetMetadataAttributes(attributes);
        }
        internal void MergeWidgetMetadataAttributes(IEnumerable<Attribute> attributes)
        {
            Select = attributes.OfType<SelectAttribute>().FirstOrDefault() ?? Select;
            DataPropertyAttribute widgetAttribute = attributes.OfType<DataPropertyAttribute>().FirstOrDefault();
            if (widgetAttribute != null)
            {
                this.QueryFormat = widgetAttribute.QueryFormat;
            }
        }
        public SelectAttribute Select { get; protected set; }
        public string QueryFormat { get; set; }

        internal void MergeDataAnnotationsMetadataAttributes(IEnumerable<Attribute> attributes)
        {
            DataType = attributes.OfType<DataTypeAttribute>().FirstOrDefault() ?? DataType;
            Display = attributes.OfType<DisplayAttribute>().FirstOrDefault() ?? Display;
            DisplayColumn = attributes.OfType<DisplayColumnAttribute>().FirstOrDefault() ?? DisplayColumn;
            DisplayFormat = attributes.OfType<DisplayFormatAttribute>().FirstOrDefault() ?? DisplayFormat;
            DisplayName = attributes.OfType<DisplayNameAttribute>().FirstOrDefault() ?? DisplayName;
            Editable = attributes.OfType<EditableAttribute>().FirstOrDefault() ?? Editable;
            HiddenInput = attributes.OfType<HiddenInputAttribute>().FirstOrDefault() ?? HiddenInput;
            ReadOnly = attributes.OfType<ReadOnlyAttribute>().FirstOrDefault() ?? ReadOnly;
            Required = attributes.OfType<RequiredAttribute>().FirstOrDefault() ?? Required;
            ScaffoldColumn = attributes.OfType<ScaffoldColumnAttribute>().FirstOrDefault() ?? ScaffoldColumn;

            var uiHintAttributes = attributes.OfType<UIHintAttribute>();
            UIHint = uiHintAttributes.FirstOrDefault(a => String.Equals(a.PresentationLayer, "MVC", StringComparison.OrdinalIgnoreCase))
                     ?? uiHintAttributes.FirstOrDefault(a => String.IsNullOrEmpty(a.PresentationLayer)) ?? UIHint;

            if (DisplayFormat == null && DataType != null)
            {
                DisplayFormat = DataType.DisplayFormat;
            }
        }

        public IEnumerator<Attribute> GetEnumerator()
        {
            return this.Attributes.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }
        /*
   * DisplayColumnAttribute
   * HiddenInputAttribute
   * UIHintAttribute
   * EditableAttribute
   * ReadOnlyAttribute
   * DataTypeAttribute
   * DisplayFormatAttribute
   * SetFromDataTypeAndDisplayAttributes
   * DisplayFormatAttribute
   * ScaffoldColumnAttribute
   * DisplayNameAttribute
   * RequiredAttribute
   * 
   * StringLengthAttribute
   * MaxLengthAttribute
   * MinLengthAttribute
   * 
   * DataType
   * RangeAttribute
   * RegularExpressionAttribute
   * RequiredAttribute
   * MembershipPasswordAttribute
   * DataAnnotationsCompareAttribute
   * FileExtensionsAttribute
   * CreditCardAttribute
   * EmailAddressAttribute
   * PhoneAttribute
   * UrlAttribute
   * RemoteAttribute
   */

    }
}
